package com.yonge.cooleshow.biz.dal.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonge.cooleshow.biz.dal.dao.CourseScheduleDao;
import com.yonge.cooleshow.biz.dal.dao.StudentDao;
import com.yonge.cooleshow.biz.dal.dao.StudentStarDao;
import com.yonge.cooleshow.biz.dal.entity.Student;
import com.yonge.cooleshow.biz.dal.enums.CacheNameEnum;
import com.yonge.cooleshow.biz.dal.service.SysConfigService;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.yonge.cooleshow.biz.dal.entity.StudentTotal;
import com.yonge.cooleshow.biz.dal.vo.StudentTotalVo;
import com.yonge.cooleshow.biz.dal.dto.search.StudentTotalSearch;
import com.yonge.cooleshow.biz.dal.dao.StudentTotalDao;
import com.yonge.cooleshow.biz.dal.service.StudentTotalService;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;


@Service
public class StudentTotalServiceImpl extends ServiceImpl<StudentTotalDao, StudentTotal> implements StudentTotalService {
    private final static Logger log = LoggerFactory.getLogger(StudentTotalServiceImpl.class);
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private StudentStarDao studentStarDao;
    @Autowired
    private CourseScheduleDao courseScheduleDao;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public StudentTotalVo detail(Long id) {
        return baseMapper.detail(id);
    }

    @Override
    public IPage<StudentTotalVo> selectPage(IPage<StudentTotalVo> page, StudentTotalSearch query) {
        return page.setRecords(baseMapper.selectPage(page, query));
    }

    @Override
    public List<StudentTotal> queryStudentTotal() {
        List<Student> students = studentDao.selectList(Wrappers.<Student>emptyWrapper()
                .select("userId"));
        //查询关注老师数
        List<StudentTotalVo> studentStarTotal = studentStarDao.queryStudentTotal();
        Map<Long, StudentTotalVo> studentStarMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(studentStarTotal)) {
            studentStarMap = studentStarTotal.stream().collect(Collectors.toMap(StudentTotalVo::getUserId, o -> o));
        }

        //查询已上未上课时数
        List<StudentTotalVo> studentCourseTotal = courseScheduleDao.queryStudentTotal();
        Map<Long, StudentTotalVo> studentCourseMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(studentCourseTotal)) {
            studentCourseMap = studentCourseTotal.stream().collect(Collectors.toMap(StudentTotalVo::getUserId, o -> o));
        }
        List<StudentTotal> resultList = new ArrayList<>();
        for (Student student : students) {
            StudentTotal studentTotal = new StudentTotal();
            studentTotal.setUserId(student.getUserId());
            StudentTotalVo starTotal = studentStarMap.get(student.getUserId());
            if (null != starTotal && null != starTotal.getStarTeacherNum()) {
                studentTotal.setStarTeacherNum(starTotal.getStarTeacherNum());
            }
            StudentTotalVo courseTotal = studentCourseMap.get(student.getUserId());
            if (null != courseTotal) {
                if (null != courseTotal.getFinshHours()) {
                    studentTotal.setFinshHours(courseTotal.getFinshHours());
                }
                if (null != courseTotal.getUnfinshHours()) {
                    studentTotal.setUnfinshHours(courseTotal.getUnfinshHours());
                }
            }
            //todo 缺少累计练习天数 累计练习时长 累计评测次数
            resultList.add(studentTotal);
            redissonClient.getBucket(CacheNameEnum.STUDENT_TOTAL.getRedisKey(studentTotal.getUserId()))
                    .set(studentTotal);
        }
        saveOrUpdateBatch(resultList);
        return resultList;
    }

    int batchSize = 100;

    /***
     * 批量更新插入
     * @author liweifan
     * @param: resultList
     * @updateTime 2022/4/12 16:52
     */
    private void saveOrUpdateBatch(List<StudentTotal> resultList) {
        List<StudentTotal> studentTotals = baseMapper.selectList(Wrappers.<StudentTotal>emptyWrapper().select("userId"));
        Map<Long, StudentTotal> studentTotalMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(studentTotals)) {
            studentTotals.forEach(o -> studentTotalMap.put(o.getUserId(), o));
        }
        //批量插入
        List<StudentTotal> saveList = resultList.stream()
                .filter(o -> null == studentTotalMap.get(o.getUserId())).collect(Collectors.toList());
        batchOpera(saveList, this::saveBatch);

        //批量更新
        List<StudentTotal> updateList = resultList.stream()
                .filter(o -> null != studentTotalMap.get(o.getUserId())).collect(Collectors.toList());
        batchOpera(updateList, this::updateBatch);
    }

    private void batchOpera(List<StudentTotal> resultList, Consumer<List<StudentTotal>> action) {
        int start = 0;
        while (true) {
            int end = start + batchSize;
            List<StudentTotal> subList;
            if (resultList.size() > end) {
                subList = resultList.subList(start, start + batchSize);
            } else {
                subList = resultList.subList(start, resultList.size());
            }
            //处理sql
            action.accept(subList);
            if (end >= resultList.size()) {
                break;
            }
            start += batchSize;
        }
    }

    private void updateBatch(List<StudentTotal> resultList) {
        for (StudentTotal total : resultList) {
            updateById(total);
        }
    }
}