package cn.exploring.engine.server.db.service;

import cn.exploring.engine.server.db.dao.LessonInfoMapper;
import cn.exploring.engine.server.db.dao.SpecialSqlMapper;
import cn.exploring.engine.server.db.dao.UserLessonInfoMapper;
import cn.exploring.engine.server.db.dao.UserReduceInfoMapper;
import cn.exploring.engine.server.db.domain.*;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Liu_c
 */
@Service
public class LessonInfoService {
    @Resource
    private LessonInfoMapper lessonInfoMapper;

    @Resource
    private UserLessonInfoMapper userLessonInfoMapper;

    @Resource
    private SpecialSqlMapper specialSqlMapper;

    @Resource
    private UserReduceInfoMapper userReduceInfoMapper;

    public Map selectLessonInfo(Integer id, Integer chapters,  String chaptersName, Integer session, String sessionName, Integer page, Integer limit, String sort, String order){
        LessonInfoExample example = new LessonInfoExample();
        LessonInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false);
        if (id != null && id > 0) {
            criteria.andIdEqualTo(id);
        }
        if (chapters != null && chapters > 0) {
            criteria.andChaptersEqualTo(chapters);
        }
        if (!StringUtils.isEmpty(chaptersName)) {
            criteria.andChaptersNameLike("%" + chaptersName + "%");
        }
        if (session != null && session > 0) {
            criteria.andSessionEqualTo(session);
        }
        if (!StringUtils.isEmpty(sessionName)) {
            criteria.andSessionNameLike("%" + sessionName + "%");
        }
        PageHelper.startPage(page, limit);
        if (!StringUtils.isEmpty(sort) && !StringUtils.isEmpty(order)) {
            example.setOrderByClause(sort + " " + order + " , add_time asc");
        }
        List<LessonInfo> lessonInfoList = lessonInfoMapper.selectByExample(example);
        long total = PageInfo.of(lessonInfoList).getTotal();
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("total", total);
        dataMap.put("items", lessonInfoList);
        return dataMap;
    }

    public List<LessonInfo> selectLessonInfo(Integer id, Integer chapters,  String chaptersName, Integer session, String sessionName, List<Integer> idList){
        LessonInfoExample example = new LessonInfoExample();
        LessonInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false);
        if (id != null && id > 0) {
            criteria.andIdEqualTo(id);
        }
        if (chapters != null && chapters > 0) {
            criteria.andChaptersEqualTo(chapters);
        }
        if (!StringUtils.isEmpty(chaptersName)) {
            criteria.andChaptersNameLike("%" + chaptersName + "%");
        }
        if (session != null && session > 0) {
            criteria.andSessionEqualTo(session);
        }
        if (!StringUtils.isEmpty(sessionName)) {
            criteria.andSessionNameLike("%" + sessionName + "%");
        }
        if (idList != null && idList.size() > 0) {
            criteria.andIdIn(idList);
        }
        example.setOrderByClause(" lesson_order asc ");
        return lessonInfoMapper.selectByExample(example);
    }

    public String addLessonInfo(LessonInfo lessonInfo) {
        List<LessonInfo> lessonInfoList = selectLessonInfo(null, lessonInfo.getChapters(),null,  lessonInfo.getSession(), null, null);
        if (lessonInfoList.size() != 0) {
            return "当前已存在第 " + lessonInfo.getChapters() + "章   第 " + lessonInfo.getSession() + "节的内容。 请检查输入的内容";
        }
        LocalDateTime now = LocalDateTime.now();
        lessonInfo.setAddTime(now);
        lessonInfo.setUpdateTime(now);
        lessonInfo.setDeleted(false);
        // todo 方便当前阶段进行取数的排序字段
        lessonInfo.setLessonOrder(lessonInfo.getChapters() * 10000 + lessonInfo.getSession());
        lessonInfoMapper.insertSelective(lessonInfo);
        return "insert Ok";
    }

    public Object updateLessonInfo(LessonInfo lessonInfo) {
        List<LessonInfo> lessonInfoList = selectLessonInfo(null, lessonInfo.getChapters(),null,  lessonInfo.getSession(), null, null);
        // 有其他唯一索引  且 id不同的情况下 进行更新。会唯一索引报错  这里检查出来直接报错
        if (lessonInfoList != null && lessonInfoList.size() != 0) {
            lessonInfoList = lessonInfoList.stream().filter(x -> !x.getId().equals(lessonInfo.getId())).collect(Collectors.toList());
        }
        if (lessonInfoList.size() != 0) {
            return "当前已存在第 " + lessonInfo.getChapters() + "章   第 " + lessonInfo.getSession() + "节的内容。 请检查更新输入的内容";
        }
        if (lessonInfo.getSession() == null || lessonInfo.getChapters() == null) {
            return "章节信息为空， 拒绝更新";
        }
        lessonInfo.setLessonOrder(lessonInfo.getChapters() * 10000 + lessonInfo.getSession());
        LocalDateTime now = LocalDateTime.now();
        lessonInfo.setAddTime(now);
        lessonInfo.setUpdateTime(now);
        lessonInfoMapper.updateByPrimaryKey(lessonInfo);
        return "update OK";
    }

    public String batchDeletedLessonInfo(List<Integer> lessonIdList) {
        List<LessonInfo> lessonInfoList = selectLessonInfo(null, null, null, null, null, lessonIdList);
        LocalDateTime now = LocalDateTime.now();
        lessonInfoList.forEach(x -> {
            x.setUpdateTime(now);
            x.setDeleted(null);
            updateLessonInfo(x);
        });
        return "batch deleted ok";
    }

    public UserLessonInfo initUserLessonInfoData(Integer userId, Integer chaptersId, Integer sessionId,  Integer selectId) {
        UserLessonInfo userLessonInfo = new UserLessonInfo();
        userLessonInfo.setUserId(userId);
        userLessonInfo.setChaptersId(chaptersId);
        userLessonInfo.setSessionId(sessionId);
        userLessonInfo.setSelectId(selectId);
        LocalDateTime now = LocalDateTime.now();
        userLessonInfo.setAddTime(now);
        userLessonInfo.setUpdateTime(now);
        userLessonInfo.setDeleted(false);
        return userLessonInfo;
    }

    /**
     * 检查是否完成了课程的学习
     * @param userId
     * @return
     */
    public boolean checkFinishLesson(Integer userId) {
        return "0".equals(specialSqlMapper.selectUnfinishLessonCount(userId).get("count_info").toString());
    }

    /**
     * 提交用户的学习记录
     * @param userId
     * @param chaptersId
     * @param sessionId
     * @param selectId
     * @return
     */
    public Object commitUserLessonRecord(Integer userId, Integer chaptersId, Integer sessionId,  Integer selectId) {
        List<UserLessonInfo> rawUserLessonInfoList =  selectUserLearnReocrd(userId, chaptersId, sessionId, null, null, null);
        UserLessonInfo userLessonInfo;

        // 当学习记录不存在的情况下  需要对数据进行新建  否则仅更新选项记录及更新时间
        if (rawUserLessonInfoList == null || rawUserLessonInfoList.size() == 0) {
            userLessonInfo = initUserLessonInfoData(userId, chaptersId, sessionId, selectId);
            userLessonInfoMapper.insertSelective(userLessonInfo);
        } else {
            userLessonInfo = rawUserLessonInfoList.get(0);
            userLessonInfo.setUpdateTime(LocalDateTime.now());
            userLessonInfo.setSelectId(selectId);
            userLessonInfoMapper.updateByPrimaryKey(userLessonInfo);
        }
        // 如果提交的时候 完成了所有的课后选择 就重新计算用户的平均得分
        if (checkFinishLesson(userId)) {
            saveUserAveragePointRecord(userId);
        }
        return "commit Ok";
    }

    public List<Map> getAllChaptersInfo() {
        return specialSqlMapper.selectAllChaptersInfo();
    }

    /**
     * 根据课程的排序字段 获取用户的下一个课程
     * @param lessonOrder
     * @return
     */
    public LessonInfo selectUserNextLesson(Integer lessonOrder) {
        LessonInfoExample example = new LessonInfoExample();
        LessonInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false).andLessonOrderGreaterThan(lessonOrder);
        example.setOrderByClause("lesson_order asc");
        return lessonInfoMapper.selectOneByExample(example);
    }

    /**
     * 根据条件查找用户的学习记录
     * @param userId
     * @param chaptersId
     * @param sessionId
     * @param selectId
     * @param sort
     * @param order
     * @return
     */
    public List<UserLessonInfo> selectUserLearnReocrd(Integer userId, Integer chaptersId, Integer sessionId, Integer selectId, String sort, String order) {
        UserLessonInfoExample example = new UserLessonInfoExample();
        UserLessonInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false);
        if (userId != null && userId > 0) {
            criteria.andUserIdEqualTo(userId);
        }
        if (chaptersId != null && chaptersId > 0) {
            criteria.andChaptersIdEqualTo(chaptersId);
        }
        if (sessionId != null && sessionId > 0) {
            criteria.andSessionIdEqualTo(sessionId);
        }
        if (selectId != null && selectId > 0) {
            criteria.andSelectIdEqualTo(selectId);
        }

        if (order == null || sort == null) {
            example.setOrderByClause("update_time desc");
        } else {
            example.setOrderByClause(sort + " " + order);
        }
        return userLessonInfoMapper.selectByExample(example);
    }

    /**
     * 获取用户最后一次学习的课程数据
     * @param userId
     * @return
     */
    public UserLessonInfo selectLastUserLearnLesson(Integer userId) {
        UserLessonInfoExample example = new UserLessonInfoExample();
        UserLessonInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false).andUserIdEqualTo(userId);
        example.setOrderByClause("update_time desc, chapters_id desc, session_id  desc ");
        return userLessonInfoMapper.selectOneByExample(example);
    }

    public Map getUserLessonInfo(Integer userId) {
        // 如果是未登陆的话直接给最早的一节课
        if (userId == null || userId < 0 || selectLastUserLearnLesson(userId) == null) {
            LessonInfo lessonInfo = selectLessonInfo(null, 1, null, 1, null, null).get(0);
            if (lessonInfo != null) {
                Map lessonData = JSON.parseObject(JSON.toJSONString(lessonInfo), Map.class);
                lessonData.put("isLastLesson", false);
                return lessonData;
            } else {
                return new HashMap() {{
                    put("isLastLesson", false);
                }};

            }
        }
        UserLessonInfo lastLessonInfo = selectLastUserLearnLesson(userId);

        LessonInfo lessonInfo;
        // 如果只是观看但是没有进行答题的话
        if (lastLessonInfo.getSelectId() == null) {
            lessonInfo = selectLessonInfo(null, lastLessonInfo.getChaptersId(), null, lastLessonInfo.getSessionId(), null, null).get(0);
        } else {
            lessonInfo = selectUserNextLesson(lastLessonInfo.getChaptersId() * 10000 + lastLessonInfo.getSessionId());
        }


        // 当用户学习完了所有课程 直接计算平均分并入库
        if (lessonInfo == null) {
            saveUserAveragePointRecord(userId);
            lessonInfo = selectLessonInfo(null, lastLessonInfo.getChaptersId(), null, lastLessonInfo.getSessionId(), null, null).get(0);
        } else {
            commitUserLessonRecord(userId, lessonInfo.getChapters(), lessonInfo.getSession(), null);
        }

        Map lessonData = JSON.parseObject(JSON.toJSONString(lessonInfo), Map.class);
        lessonData.put("isLastLesson", selectUserNextLesson(lessonInfo.getLessonOrder()) == null);
        return lessonData;

    }

    public Map getUserLessonInfoByLessonId (Integer userId, Integer lessonId) {
        List<LessonInfo> lessonInfoList = selectLessonInfo(lessonId, null, null, null, null, null);
        LessonInfo lessonInfo = lessonInfoList == null || lessonInfoList.size() == 0 ? null: lessonInfoList.get(0);
        commitUserLessonRecord(userId, lessonInfo.getChapters(), lessonInfo.getSession(), null);
        if (lessonInfo != null) {
            Map lessonData = JSON.parseObject(JSON.toJSONString(lessonInfo), Map.class);
            lessonData.put("isLastLesson", selectUserNextLesson(lessonInfo.getLessonOrder()) == null);
            return lessonData;
        } else {
            return new HashMap() {{
                put("isLastLesson", true);
            }};

        }
    }

    /**
     * 计算用户的平均分
     * @param userId
     * @return
     */
    public Float calcUserAveragePoint(Integer userId) {
        List<Map> data = specialSqlMapper.selectChaptersAvgPoint(userId);
        Float sumData = data.stream().filter(x -> x.get("avg_chapters_point") != null).map(x -> Float.parseFloat(x.get("avg_chapters_point").toString())).reduce((float) 0, Float::sum);
        return sumData / data.size();
    }

    public UserReduceInfo initUserReduceInfo(Integer userId) {
        UserReduceInfo userReduceInfo = new UserReduceInfo();
        userReduceInfo.setUserId(userId);
        userReduceInfo.setLessonAveragePoint(calcUserAveragePoint(userId));
        LocalDateTime now = LocalDateTime.now();
        userReduceInfo.setAddTime(now);
        userReduceInfo.setUpdateTime(now);
        userReduceInfo.setDeleted(false);
        return userReduceInfo;
    }

    /**
     * 当学员完成课程的学习之后  对历史记录计算一个平均分 并保存
     * @param userId
     * @return
     */
    public UserReduceInfo saveUserAveragePointRecord(Integer userId) {
        UserReduceInfo userReduceInfo = selectUerReduceRecord(userId);
        if (userReduceInfo == null) {
            userReduceInfo = initUserReduceInfo(userId);
            userReduceInfoMapper.insertSelective(userReduceInfo);
        } else {
            userReduceInfo.setLessonAveragePoint(calcUserAveragePoint(userId));
            userReduceInfoMapper.updateByPrimaryKey(userReduceInfo);
        }
        return userReduceInfo;
    }


    /**
     * 获取用户的历史完成课程及积分数据
     * @param userId 用户Id
     * @return
     */
    public List<Map> getUserHistoryLessonPoint(Integer userId) {
        List<Map> rawDataList =  specialSqlMapper.selectUserHistoryPointDetail(userId);
        Map<Integer, List<Map>> targetMapData = new LinkedHashMap<>();
        rawDataList.forEach(x -> {
            Integer chapters = Integer.parseInt(x.get("chapters").toString());
            if (targetMapData.get(chapters) == null) {
                List<Map> mapList = new ArrayList<>();
                mapList.add(x);
                targetMapData.put(chapters, mapList);
            } else {
                List<Map> mapList = targetMapData.get(chapters);
                mapList.add(x);
                targetMapData.put(chapters, mapList);
            }
        });

        List<Map> result = new ArrayList<>();
        targetMapData.keySet().forEach(x -> {
            Map oneData = new HashMap(){{
                put("chaptersName", targetMapData.get(x).get(0).get("chapters_name"));
                put("sessonPointList", targetMapData.get(x));
            }};
            result.add(oneData);
        });
        return result;

    }

    /**
     * 获取用户的汇总数据  含有用户的课程学习平均数据
     * @param userId
     * @return
     */
    public UserReduceInfo selectUerReduceRecord(Integer userId) {
        UserReduceInfoExample example = new UserReduceInfoExample();
        UserReduceInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDeletedEqualTo(false).andUserIdEqualTo(userId);
        return userReduceInfoMapper.selectOneByExample(example);
    }

    /**
     * 获取用户的课程平均分数据及及
     * @param userId
     * @return
     */
    public Map getUserLessonPointRank(Integer userId) {
        Map resultMap = new HashMap();
        UserReduceInfo userReduceInfo = selectUerReduceRecord(userId);
        if (userReduceInfo == null) {
            userReduceInfo = saveUserAveragePointRecord(userId);
            resultMap.put("userAveragePoint", calcUserAveragePoint(userId));
        } else {
            resultMap.put("userAveragePoint", userReduceInfo.getLessonAveragePoint());
        }
        Integer leadNum = Integer.parseInt(specialSqlMapper.selectDataCount(userReduceInfo.getLessonAveragePoint()).get("count_info").toString());
        Integer allNum = Integer.parseInt(specialSqlMapper.selectDataCount(null).get("count_info").toString());
        resultMap.put("userPointRank", Math.max(leadNum * 100 / allNum, 1));
        return resultMap;
    }

    /**
     * 获取所有杂课的目录
     * @return
     */
    public Object getAllLessonIndex() {
        List<LessonInfo> rawDataList =  selectLessonInfo(null, null, null, null, null, null);
        Map<Integer, List<LessonInfo>> targetMapData = new LinkedHashMap<>();
        rawDataList.forEach(x -> {
            Integer chapters = x.getChapters();
            if (targetMapData.get(chapters) == null) {
                List<LessonInfo> mapList = new ArrayList<>();
                mapList.add(x);
                targetMapData.put(chapters, mapList);
            } else {
                List<LessonInfo> mapList = targetMapData.get(chapters);
                mapList.add(x);
                targetMapData.put(chapters, mapList);
            }
        });
        List<Map> result = new ArrayList<>();
        targetMapData.keySet().forEach(x -> {
            Map oneData = new HashMap(){{
                put("chaptersName", targetMapData.get(x).get(0).getChaptersName());
                put("sessonDataList", targetMapData.get(x));
            }};
            result.add(oneData);
        });
        return result;
    }
}
